package com.honey.feature;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.StringReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import com.honey.core.compiler.Compilation;
import com.honey.core.feature.Feature;
import com.honey.core.utils.HexCode;

public abstract class BaseFeature implements CalculationFeature {
	
	private static final byte[] SALT= new byte[]{
		-116, -43, 101, 83, -84, -90, -103, 112, 70, -101, 47, -128, -65, 108, -86, 103, 122, -12, -60, 4
	};
	
	@Override
	public String getFeature(Compilation compilation,String charset) {
		String answer = null;
		try {
			byte[] buffer =  getContent(
					new StringReader( 
							compilation.compiledContent().toString() 
					)
					,
					charset
			);
			
			if( buffer!= null && buffer.length > 0){
				MessageDigest digest = getMessageDigest();
				digest.update(buffer);
				digest.update(SALT);
				//
				buffer = digest.digest();
				answer = new String( HexCode.encodeHex(buffer) );
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	/**
	 * 获取抽取特征的方法,默认使用MD5算法
	 * @param digest
	 * @return
	 */
	public MessageDigest getMessageDigest(){
		MessageDigest answer = null;
		try {
			answer = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return answer ;
	}
	
	@Override
	public boolean originalChecksum(File target, Feature[] features,String charset) {
		boolean answer =false;
		try {
			Reader reader =new BufferedReader( new InputStreamReader(new FileInputStream(target), "utf-8"));
			byte[] buffer = getContent(reader,charset);
			byte[] new_file = null ;
			if( buffer!= null && buffer.length > 0){
				MessageDigest digest = getMessageDigest();
				digest.update(buffer);
				digest.update(SALT);
				new_file = digest.digest();
			}
			byte[] current_file = getCurrentFeature(target,charset);
			
			answer = Arrays.equals(current_file, new_file);
		} catch (Exception e) {
			System.out.println(target.getPath());
			e.printStackTrace();
		}
		return answer;
	}
	
	public byte[] getCurrentFeature(File target,String charset) {
		byte[] answer = null ;
		try {
			ReverseReadLine rr = new ReverseReadLine(target);
			String line = null;
			do{
				line = rr.readPreviousLine(charset);
				if(line != null){
					line = line.trim();
				}
			}while( line == null || line.length() == 0 || line.equals("*/"));
			int i = line.indexOf(':');
			if( line.length() >= 34 ){
				line = line.substring(i+2, i+34);
				answer =HexCode.decodeHex(line.toCharArray()); 
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	
	/**
	 * 获取reader中有效的内容
	 * @param reader
	 * @param charset
	 * @return
	 */
	public abstract byte[] getContent(Reader reader,String charset) throws Exception;
	
	/**
	 * 从文件的最后一行读取数据
	 * @author Administrator
	 *
	 */
	protected class ReverseReadLine{
		
		private RandomAccessFile randomAccessFile = null;
		
		private long _position = 0 ;
		
		private final long _length ;
		
		public ReverseReadLine( File target ) throws IOException{
			this.randomAccessFile = new RandomAccessFile(target,"r");
			this._length = randomAccessFile.length();
			this.reset();
		}
		
		public void reset(){
			this._position = _length;
		}
		
		/**
		 * 按照文件的倒序读一行内容;
		 * @param charset
		 * @return
		 * @throws IOException
		 */
		public String readPreviousLine(String charset) throws IOException {
			String answer = null;
			int legth =0;
			byte b =0;
			while (_position > 0) {
				_position --; 
				randomAccessFile.seek(_position);
				b = randomAccessFile.readByte();
				if ( b == 10){// \n
					break;
				}else if(  b == 13){ // \r
					continue;
				}else{
					legth++;
				}
			}
			if(_position > 0 || legth > 0){
				byte[] bytes = new byte[legth];
				if(_position == 0 )randomAccessFile.seek(0);
				randomAccessFile.read(bytes);
				answer = new String(bytes,0,legth,charset == null ? "UTF-8":charset );
			}
			return answer ;
		}
		
		public void close(){
			try {
				randomAccessFile.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
